import axios, { InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig } from "axios";
import { message } from "antd";

export const baseURL:string = "http://localhost:3000"

const axiosInstance = axios.create({
    baseURL,
    timeout: 3000
});

axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
    const accessToken = localStorage.getItem("access_token");
    if(accessToken) config.headers.Authorization = "Bearer "+accessToken;
    return config;
}, error => {
    return error
});


interface PendingTask {
    config: AxiosRequestConfig;
    resolve: Function;
}
let refreshing = false;
const queue: PendingTask[] = [];

axiosInstance.interceptors.response.use((response: AxiosResponse) => {
    return response.data;
}, async (error) => {
    // Promise链式调用的一个规则，如果error返回的是一个非 Promise格式的数据，那么下一次链式调用，默认走成功的逻辑（.then）
    // return error.response.data 所以为了走到我们组件中自定义的错误逻辑，我们需要使用下面这种写法
    // return Promise.reject(error.response.data);

    // 下面我们添加token无感刷新功能
    if(!error.response) return Promise.reject(error);
    let { data, config } = error.response;
    // 将token失效后，用户又发起的请求放入队列，后续等新token请求成功后重新刷新
    if(refreshing) {
        return new Promise(resolve => {
            queue.push({
                config,
                resolve
            })
        })
    }
    // 需要排除用于刷新的token也失效时这个请求
    if(data.code === 401 && !config.url.includes("/user/refresh")) {
        refreshing = true;
        const res = await refreshToken();
        refreshing = false;
        if(res.status === 200) {
            // 重新发起 token失效后，用户新发的请求（refreshing为true时进来的那些请求）
            queue.forEach(({config, resolve}) => {
                resolve(axiosInstance(config));
            })
            // 重新发起 当前因为token失效而失败的请求（refreshing为false时的那一个请求，具体就是触发刷新token的那个请求）
            return axiosInstance(config);
        }else {// 用于刷新的token也失效时，重新登录；
            message.error(res.data);
            setTimeout(()=>{
                window.location.href = "/login";
            }, 1500)
        }
    }else {
        return Promise.reject(error.response.data);
    }
    
})

async function refreshToken() {
    const res = await axiosInstance.get("/user/refresh", {
        params: { refresh_token: localStorage.getItem("refresh_token") }
    });
    localStorage.setItem('access_token', res.data.access_token || '')
    localStorage.setItem('refresh_token', res.data.refresh_token || '')
    return res;
}


export default axiosInstance;